package com.ruantong.dingtalk.ding.openapi.token;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruantong.dingtalk.ding.openapi.GetTokenApi;
import com.ruantong.dingtalk.enums.DingConfigTypeEnum;
import com.ruantong.dingtalk.model.DingConfig;
import com.ruantong.dingtalk.service.DingConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.Instant;
import java.util.Date;

/**
 * @description:token的工具类，同时维护token的合法性
 * @author: jh.chen
 * @time: 2020/11/14 9:59
 */
@Slf4j
@Component
public class DingTokenStore {
    /**
     * token
     */
    private static String TOKEN;
    private final static String TOKEN_KEY = "token";
    /**
     * 持有的token过期时间
     */
    private static Instant EXPIRES;
    private final static String EXPIRES_KEY = "expires";
    /**
     * EXPIRES_TIME,钉钉的token过期时间(SECONDS)
     */
    private static final Integer EXPIRES_TIME = 7200;
    /**
     * 漂移时间
     */
    private static final Integer TIME_DRIFT = 10;

    public String getToken() {
        if (isExpires()) {
            refreshToken();
            updateConfig();
        }
        return TOKEN;
    }

    public boolean isExpires() {
        return Instant.now().isAfter(EXPIRES.minusSeconds(TIME_DRIFT));
    }

    @Autowired
    private GetTokenApi getTokenApi;

    @Autowired
    private DingConfigService dingConfigService;

    @PostConstruct
    public void getTokenInit() {
        String token = dingConfigService.getToken();
        if (token == null) {
            if (refreshToken()) {
                insertConfig();
            }
        }
        if (TOKEN != null) {
            return;
        }
        //数据库取出
        JSONObject json = JSON.parseObject(token);
        TOKEN = json.getString(TOKEN_KEY);
        EXPIRES = Instant.parse(json.getString(EXPIRES_KEY));
        log.info("GetToken init!");
    }

    private boolean refreshToken() {
        String tokenNew = getTokenApi.getToken();
        if (TOKEN != null && TOKEN.equals(tokenNew)) {
            return false;
        }
        Instant instant = Instant.now().plusSeconds(EXPIRES_TIME);
        TOKEN = tokenNew;
        EXPIRES = instant;
        log.info("RefreshToken,token:{},expires:{}", TOKEN, EXPIRES);
        return true;
    }

    private void insertConfig() {
        DingConfig dingConfig = new DingConfig();
        JSONObject json = new JSONObject();
        json.put(TOKEN_KEY, TOKEN);
        json.put(EXPIRES_KEY, EXPIRES);
        dingConfig.setData(json.toJSONString());
        dingConfig.setType(DingConfigTypeEnum.DING_TOKEN_CONFIG.value().byteValue());
        Date now = new Date();
        dingConfig.setGmtCreate(now);
        dingConfig.setGmtModify(now);
        dingConfigService.insert(dingConfig);
    }

    private void updateConfig() {
        String tokenInfo = dingConfigService.getToken();
        JSONObject json = JSON.parseObject(tokenInfo);
        if (json.getString(TOKEN_KEY).equals(TOKEN)) {
            return;
        }
        DingConfig dingConfig = new DingConfig();
        JSONObject jsonNew = new JSONObject();
        jsonNew.put(TOKEN_KEY, TOKEN);
        jsonNew.put(EXPIRES_KEY, EXPIRES);
        dingConfig.setData(jsonNew.toJSONString());
        Date now = new Date();
        dingConfig.setGmtModify(now);
        dingConfigService.update(dingConfig);
    }

}
